import { FormItemRule } from "element-plus";
import { reactive, ref, UnwrapNestedRefs } from "vue";
import { getCustomRule, passWordRule } from "..";
import { InputUI, SFSchema, SFUISchemaItem } from "../interface";

export class BaseService<T extends SFUISchemaItem> {
  protected _schema: SFSchema<T>;
  protected _required: boolean;
  protected _ui: UnwrapNestedRefs<T>;
  private _visible = true;
  asyncChangeValid = ref(true);
  protected _params: UnwrapNestedRefs<Omit<SFSchema<T>, "ui">>;
  constructor(schema: SFSchema<T>, required: boolean) {
    this._schema = schema;
    const { ui, ...arg } = schema;
    this._ui = reactive<T>({ ...ui });
    this._params = reactive<Omit<SFSchema<T>, "ui">>(arg);
    this._required = required;
  }

  get schema() {
    return this._schema;
  }
  get ui() {
    return this._ui;
  }
  get params() {
    return this._params;
  }

  get nxtFormat() {
    return this._ui.nxtFormat;
  }
  get preFormat() {
    return this._ui.preFormat;
  }

  get widget() {
    let widget = this._ui?.widget;
    if (!widget) {
      if (this._params?.type === "number") {
        widget = "inputNumber";
      }
      if (this._params?.type === "boolean") {
        widget = "switch";
      }
    }
    return widget || "input";
  }

  get title() {
    return this._params?.title ?? "";
  }
  get size() {
    return this._ui?.size ?? "default";
  }

  get placeholder() {
    const ui = this._ui || ({} as T);
    return ui?.placeholder || "";
  }

  get labelWidth() {
    const ui = this._ui || ({} as T);
    return ui.grid?.spanLabel || 80;
  }

  get span() {
    const ui = this._ui || ({} as T);
    return ui.grid?.span || 24;
  }

  get readonly() {
    return this._params.readonly;
  }

  get acl() {
    const ui = this._ui || ({} as T);
    return ui?.acl;
  }

  get change() {
    const ui = this._ui || ({} as T);
    return ui?.change;
  }

  setVisible(visible: boolean) {
    this._visible = visible;
  }

  get visible() {
    return this._visible;
  }

  get validate() {
    const rules = [] as FormItemRule[];
    const passWordUi = this._ui as InputUI;
    if (
      this.widget === "input" &&
      passWordUi.vaildPassword &&
      passWordUi.showPassword
    ) {
      rules.push(passWordRule);
    }

    if (this._ui?.customVaild && this._ui.customVaild?.length > 1) {
      const [regex, msg, trigger] = this._ui.customVaild;
      rules.push(getCustomRule(regex, msg, trigger));
    }
    if (this._required) {
      rules.push({
        required: true,
        message: "必填项，请填写",
        trigger: "blur"
      });
    }
    const ui = this._ui || ({} as T);

    if (ui?.asyncValidate) {
      rules.push({
        asyncValidator: async (_: any, value: any, callback: any) => {
          if (value) {
            const valid = await (ui.asyncValidate(value) as Promise<boolean>);
            this.asyncChangeValid.value = !valid;
            if (valid) {
              callback(new Error(ui?.errorMsg || "校验不通过"));
            } else {
              callback();
            }
          } else {
            callback();
          }
        },
        message: ui?.errorMsg || "校验不通过",
        trigger: ["change"]
      });
    }
    if (ui?.validate) {
      rules.push({
        validator: (_: any, value: any) => {
          return ui.validate(value) as boolean;
        },
        message: ui?.errorMsg || "校验不通过",
        trigger: "blur"
      });
    }
    if (this._params?.format) {
      let regex = null;
      let msg = "";
      switch (this._params.format) {
        case "mobile":
          regex = /^1[3456789]\d{9}$/;
          msg = "手机号验证失败，请重新输入";
          break;
        case "idCard":
          regex =
            /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01])\d{3}[\dXx]$/;
          msg = "身份证验证失败，请重新输入";
          break;
        case "email":
          regex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
          msg = "邮箱验证失败，请重新输入";
          break;
        case "chinese":
          regex = /^[\u4e00-\u9fa5]+$/i;
          msg = "当前输入，只能包含中文";
          break;
        case "noChinese":
          regex = /^[a-zA-Z0-9_]{0,}$/;
          msg = "当前输入，不能包含中文和特殊字符";
          break;
        case "url":
          // eslint-disable-next-line no-case-declarations
          const strRegex =
            "^((https|http|ftp|rtsp|mms)?://)" +
            "?(([0-9a-z_!~*().&=+$%-]+: )?[0-9a-z_!~*().&=+$%-]+@)?" + //ftp的user@
            "(([0-9]{1,3}.){3}[0-9]{1,3}" + // IP形式的URL- 199.194.52.184
            "|" + // 允许IP和DOMAIN（域名）
            "([0-9a-z_!~*()-]+.)*" + // 域名- www.
            "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]." + // 二级域名
            "[a-z]{2,6})" + // first level domain- .com or .museum
            "(:[0-9]{1,4})?" + // 端口- :80
            "((/?)|" + // a slash isn't required if there is no file name
            "(/[0-9a-z_!~*().;?:@&=+$,%#-]+)+/?)$";
          regex = new RegExp(strRegex);
          msg = "请输入正确得url地址";
          break;
      }
      if (regex) {
        rules.push({
          validator: (_: any, value: any) => {
            return regex.test(value);
          },
          message: msg,
          trigger: "blur"
        });
      }
    }
    return rules;
  }
}
